<?php

namespace maotool\file;

use maotool\http\HttpRequest;
use maotool\http\HttpUtil;
use maotool\object\StrUtil;
use maotool\util\DateUtil;
use maotool\util\IdUtil;
use maotool\util\PathUtil;

class FileUtil
{

    /**
     * 缓存
     * @var array
     */
    public static $cache = [];

    /**
     * 读取文件
     * @param $path
     * @return false|string
     */
    public static function read($path)
    {
        $path = self::path($path);
        if (isset(self::$cache[$path])
            && self::$cache[$path]["createTime"] == self::createTime($path)
            && self::$cache[$path]["updateTime"] == self::updateTime($path)) {
            ++self::$cache[$path]["readCount"];
            self::$cache[$path]["readTime"] = DateUtil::date();
            return self::$cache[$path]['content'];
        }
        $handle = fopen($path, "r");
        $content = fread($handle, filesize($path));
        fclose($handle);
        self::$cache[$path] = [
            'readCount' => 1,
            'readTime' => DateUtil::date(),
            'content' => $content,
            'createTime' => self::createTime($path),
            'updateTime' => self::updateTime($path)
        ];
        return $content;
    }

    /**
     * 读取指定行文件
     * @param $path
     * @param $index
     * @return mixed
     */
    public static function readLine($path, $index)
    {
        $path = self::path($path);
        $file = file($path);
        return $file[$index];
    }

    /**
     * 读取指定行文件
     * @param $url
     * @param $path
     * @return void
     */
    public static function download($url, $path)
    {
        $path = self::path($path);
        $content = file_get_contents($url);
        self::write($path, $content);
    }

    /**
     * 读取JSON文件
     * @param $path
     * @return mixed
     */
    public static function readJson($path)
    {
        if (isset(self::$cache[$path.":json"])
            && self::$cache[$path.":json"]["createTime"] == self::createTime($path)
            && self::$cache[$path.":json"]["updateTime"] == self::updateTime($path)) {
            return self::$cache[$path.":json"]['json'];
        }
        $json = self::read($path);
        $json = json_decode($json, true);
        self::$cache[$path.":json"] = [
            'json' => $json,
            'createTime' => self::createTime($path),
            'updateTime' => self::updateTime($path)
        ];
        return $json;
    }

    /**
     * 写入文件
     * @param $path
     * @param $content
     * @return void
     */
    public static function write($path, $content)
    {
        $path = self::path($path);
        DirUtil::create(DirUtil::dirName($path));
        $handle = fopen($path, 'w');
        fwrite($handle, $content);
        fclose($handle);
    }

    /**
     * 创建文件
     * @param $path
     * @param $content
     * @return void
     */
    public static function create($path, $content = '')
    {
        $path = self::path($path);
        DirUtil::create(DirUtil::dirName($path));
        $handle = fopen($path, 'w');
        fwrite($handle, $content);
        fclose($handle);
    }

    /**
     * 写入JSON文件
     * @param $path
     * @param $content
     * @return void
     */
    public static function writeJson($path, $content)
    {
        self::write($path, json_encode($content, JSON_UNESCAPED_UNICODE));
    }

    /**
     * 追加内容到文件
     * @param $path
     * @param $content
     * @return void
     */
    public static function append($path, $content)
    {
        $path = self::path($path);
        $file = fopen($path, "a");
        fwrite($file, $content);
        fclose($file);
    }

    /**
     * 追加一行内容到文件+
     * @param $path
     * @param $content
     * @return void
     */
    public static function appendLine($path, $content)
    {
        self::append($path, $content . "\n");
    }

    /**
     * 文件大小
     * @param $path
     * @return false|int
     */
    public static function size($path)
    {
        $path = self::path($path);
        return filesize($path);
    }

    /**
     * 文件行数
     * @param $path
     * @return int
     */
    public static function line($path)
    {
        $path = self::path($path);
        $file = file($path);
        return count($file);
    }

    /**
     * 拷贝文件
     * @return void
     */
    public static function copy($originalPath, $targetPath)
    {
        $originalPath = self::path($originalPath);
        if (self::exist($originalPath)) {
            $targetPath = self::path($targetPath);
            copy($originalPath, $targetPath);
        }
    }

    /**
     * 删除文件
     * @return bool
     */
    public static function delete($path)
    {
        $path = self::path($path);
        if (file_exists($path) && is_file($path) && is_writable($path) && is_readable($path)) {
            unlink($path);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 文件是否有权限读写
     * @return bool
     */
    public static function permission($path)
    {
        $path = self::path($path);
        if (file_exists($path) && is_file($path) && is_writable($path) && is_readable($path)) {
            return true;
        }
        return false;
    }

    /**
     * 创建时间
     * @return string
     */
    public static function createTime($path = __DIR__)
    {
        $path = self::path($path);
        return date('Y-m-d H:i:s', filectime($path));
    }

    /**
     * 修改时间
     * @return string
     */
    public static function updateTime($path = __DIR__)
    {
        $path = self::path($path);
        return date('Y-m-d H:i:s', filemtime($path));
    }

    /**
     * 是否存在
     * @param $path
     * @return bool
     */
    public static function exist($path)
    {
        $path = self::path($path);
        return file_exists($path) && is_file($path);
    }

    /**
     * 是否不存在
     * @param $path
     * @return bool
     */
    public static function notExist($path)
    {
        return !self::exist($path);
    }

    /**
     * 路径
     * @param ...$path
     * @return string
     */
    public static function path(...$path)
    {
        return PathUtil::path(...$path);
    }

    /**
     * 创建系统的临时文件
     * @param $path
     * @return string
     */
    public static function createSystemTempFile($path = null)
    {
        if (is_null($path)) {
            $path = IdUtil::simpleUUID() . ".tmp";
        }
        $path = DirUtil::getSystemTemp() . DirUtil::$DIRECTORY_SEPARATOR . $path;
        self::create($path);
        return $path;
    }

    /**
     * 是否是php文件
     * @return bool
     */
    public static function isPhpFile($path)
    {
        $path = self::path($path);
        if (file_exists($path) && is_file($path)) {
            $content = FileUtil::read($path);
            if (StrUtil::startsWith($content, "<?php")) {
                return true;
            }
        }
        return false;
    }

    /**
     * 是否是php类文件
     * @return bool
     */
    public static function isPhpClassFile($path)
    {
        $path = self::path($path);
        if (file_exists($path) && is_file($path)) {
            $content = FileUtil::read($path);
            if (StrUtil::startsWith(StrUtil::trim($content), "<?php")) {
                $fileLines = preg_split("/\r\n|\n|\r/", $content);
                foreach ($fileLines as $fileLine) {
                    if (StrUtil::startsWith(StrUtil::trim($fileLine), "class")) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 是否是php脚本非类文件
     * @return bool
     */
    public static function isPhpScriptFile($path)
    {
        $path = self::path($path);
        if (file_exists($path) && is_file($path)) {
            $content = FileUtil::read($path);
            if (StrUtil::startsWith(StrUtil::trim($content), "<?php")) {
                $fileLines = preg_split("/\r\n|\n|\r/", $content);
                foreach ($fileLines as $fileLine) {
                    if (StrUtil::startsWith(StrUtil::trim($fileLine), "class")) {
                        return false;
                    }
                }
                return true;
            }
        }
        return false;
    }

}